from django.test import TestCase
from django.urls import reverse
from rest_framework.test import APITestCase
from rest_framework import status
from datetime import datetime
from django.utils import timezone
from django.contrib.auth import get_user_model

from .models import alert
from apps.devices.models import Device
from apps.rooms.models import Room


class AlertViewsTest(APITestCase):
    """
    报警管理相关接口的测试用例集

    测试覆盖：
    1. 报警历史记录获取接口 (AlertHistory)
    2. 报警详情获取接口 (AlertDetail)
    """

    def setUp(self):
        """
        测试前的准备工作：创建测试设备和报警数据，并直接认证测试客户端
        """
        # 创建一个用于认证的测试用户
        User = get_user_model()
        User.objects.filter(username='testuser').delete()
        self.user = User.objects.create_user(username='testuser', password='testpassword')

        # 使用 APITestCase 的 force_authenticate 直接认证客户端
        self.client.force_authenticate(user=self.user)

        # 创建一个房间
        self.test_room = Room.objects.create(name="测试房间")

        # 创建测试设备
        self.test_device = Device.objects.create(
            device_name="测试设备1",
            device_type="温度传感器",
            room=self.test_room,
            status="online"
        )

        # 创建多个测试报警记录
        self.test_alerts = []
        alert_types = ["温度过高", "温度过低", "设备离线"]
        alert_levels = ["高", "中", "低"]

        for i in range(3):
            new_alert = alert.objects.create(  # 使用大写的 Alert
                alert_type=alert_types[i],
                trigger_time=timezone.now(),
                device=self.test_device,
                level=alert_levels[i]
            )
            self.test_alerts.append(new_alert)

        # 保存第一个报警的ID用于详情测试
        self.test_alert_id = self.test_alerts[0].alert_id

    def test_get_alert_history(self):
        """测试获取报警历史记录列表"""
        url = reverse('alert-history')  # 确保 URL 名称正确
        response = self.client.get(url)

        # 验证响应状态码
        self.assertEqual(response.status_code, status.HTTP_200_OK,
                         "获取报警历史记录失败")

        # 验证返回的数据列表长度
        self.assertEqual(len(response.data), 3,
                         "返回的报警记录数量不正确")

        # 验证返回的数据字段
        first_alert = response.data[0]
        expected_fields = ['alert_id', 'alert_type', 'trigger_time', 'device', 'level']
        for field in expected_fields:
            self.assertIn(field, first_alert,
                          f"报警记录缺少必要字段: {field}")

        # 验证报警类型是否正确
        alert_types = [alert['alert_type'] for alert in response.data]
        self.assertIn("温度过高", alert_types,
                      "未找到温度过高类型的报警记录")
        self.assertIn("温度过低", alert_types,
                      "未找到温度过低类型的报警记录")
        self.assertIn("设备离线", alert_types,
                      "未找到设备离线类型的报警记录")

    def test_get_alert_detail_success(self):
        """测试成功获取报警详情"""
        url = reverse('alert-detail', kwargs={'alert_id': self.test_alert_id})
        response = self.client.get(url)

        # 验证响应状态码
        self.assertEqual(response.status_code, status.HTTP_200_OK,
                         "获取报警详情失败")

        # 验证返回的数据字段
        expected_fields = ['alert_id', 'alert_type', 'trigger_time', 'device', 'level']
        for field in expected_fields:
            self.assertIn(field, response.data,
                          f"报警详情缺少必要字段: {field}")

        # 验证报警ID是否正确
        self.assertEqual(response.data['alert_id'], self.test_alert_id,
                         "返回的报警ID与请求的不匹配")

        # 验证报警类型是否正确
        self.assertEqual(response.data['alert_type'], "温度过高",
                         "报警类型不正确")
        self.assertEqual(response.data['level'], "高",
                         "报警级别不正确")

    def test_get_alert_detail_not_found(self):
        """测试获取不存在的报警详情"""
        non_existent_id = 9999
        url = reverse('alert-detail', kwargs={'alert_id': non_existent_id})
        response = self.client.get(url)

        # 验证响应状态码
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND,
                         "对不存在的报警ID未返回404状态码")

        # 验证错误信息
        self.assertEqual(response.data['error'], 'Alert not found',
                         "未返回正确的错误信息")

    def test_alert_history_empty(self):
        """测试在没有报警记录时获取历史记录"""
        # 清除所有报警记录
        alert.objects.all().delete()

        url = reverse('alert-history')
        response = self.client.get(url)

        # 验证响应状态码
        self.assertEqual(response.status_code, status.HTTP_200_OK,
                         "空报警记录查询失败")

        # 验证返回空列表
        self.assertEqual(len(response.data), 0,
                         "应该返回空列表")

    def tearDown(self):
        """测试结束后的清理工作"""
        # 清理所有测试数据
        Device.objects.all().delete()
        alert.objects.all().delete()  # 这将级联删除相关的Alert记录
        get_user_model().objects.all().delete()  # 清理创建的测试用户